home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / SLAX 6.0.8 / slax-6.0.8.iso / slax / tools / liblinuxlive < prev    next >
Text File  |  2008-11-21  |  31KB  |  1,087 lines

  1. #!/bin/bash
  2.  
  3. # Functions library :: for Linux Live scripts 6
  4. # Author: Tomas M. <http://www.linux-live.org>
  5. #
  6.  
  7. # ===========================================================
  8. # GLOBAL variables
  9. # ===========================================================
  10.  
  11. # linux live flag to fstab, if fstab line doesn't contain it,
  12. # never remove it from fstab automatically (user added it)
  13. FSTABLLFLAG="# AutoUpdate"
  14.  
  15. # We have to set these variables very carefully
  16. UNION=union
  17. MEMORY=memory
  18. MOUNTDIR=mnt
  19. CHANGES=$MEMORY/changes
  20. XINO=$MEMORY/xino
  21. COPY2RAM=$MEMORY/copy2ram
  22. IMAGES=$MEMORY/images
  23. INITRAMDISK=$MOUNTDIR/live
  24. LOOPMOUNT=$MOUNTDIR/tmp
  25.  
  26. # this will be replaced by build script, so never change the following line!
  27. LIVECDNAME="mylinux"
  28.  
  29. # =================================================================
  30. # debug and output functions
  31. # =================================================================
  32.  
  33. # global variable
  34. DEBUG_IS_ENABLED=$(cat /proc/cmdline 2>/dev/null | grep debug)
  35.  
  36. debug_log()
  37. {
  38.    if [ "$DEBUG_IS_ENABLED" ]; then
  39.       echo "- debug: $*" >&2
  40.       log "- debug: $*"
  41.    fi
  42. }
  43.  
  44. # echogreen will echo $@ in green color
  45. # $1 = text
  46. #
  47. echogreen()
  48. {
  49.    echo -ne """$@"""
  50. }
  51.  
  52. # echolog
  53. # $1 = text to show and to write to /var/log/messages
  54. #
  55. echolog()
  56. {
  57.    if [ "$1" != "" ]; then
  58.       echogreen "* "
  59.       log "LIVECD:" "$@" 
  60.       echo "$@"
  61.    fi
  62. }
  63.  
  64. # log
  65. # store given text in /var/log/livedbg
  66. log()
  67. {
  68.    echo "$@" 2>/dev/null >>/var/log/livedbg
  69. }
  70.  
  71. # show information about the debug shell
  72. show_debug_banner()
  73. {
  74.    echo
  75.    echo "====="
  76.    echo ": Debugging started. Here is the root shell for you."
  77.    echo ": Type your desired commands or hit Ctrl+D to continue booting."
  78.    echo
  79. }
  80.  
  81. # debug_shell
  82. # executed when debug boot parameter is present
  83. #
  84. debug_shell()
  85. {
  86.    if [ "$DEBUG_IS_ENABLED" ]; then
  87.       show_debug_banner
  88.       ash < /dev/console
  89.       echo
  90.    fi
  91. }
  92.  
  93. # header
  94. # $1 = text to show
  95. #
  96. header()
  97. {
  98.    echo """$@"""
  99. }
  100.  
  101. fatal()
  102. {
  103.    echolog
  104.    header "Fatal error occured - $1"
  105.    echolog "Something went wrong and we can't continue. This should never happen."
  106.    echolog "Please reboot your computer with Ctrl+Alt+Delete ..."
  107.    echolog
  108.    ash < /dev/console
  109. }
  110.  
  111. allow_only_root()
  112. {
  113.   # test if the script is started by root user. If not, exit
  114.   if [ "0$UID" -ne 0 ]; then
  115.      echo "Only root can run $(basename $0)"; exit 1
  116.   fi
  117. }
  118.  
  119. # ===========================================================
  120. # text processing functions
  121. # ===========================================================
  122.  
  123. # look into cmdline and echo $1 back if $1 is set
  124. # $1 = value name, case sensitive, for example 'debug'
  125. #
  126. cmdline_parameter()
  127. {
  128.    debug_log "cmdline_parameter" "$*"
  129.    log "searching for bootparam: $1"
  130.    egrep -o "(^|[[:space:]])$1([[:space:]]|\$)" /proc/cmdline | tr -d " " | tail -n 1
  131. }
  132.  
  133. # look into cmdline and echo value of $1 option
  134. # $1 = value name, case sensitive, for example 'changes'
  135. #
  136. cmdline_value()
  137. {
  138.    debug_log "cmdline_value" "$*"
  139.    log "searching for bootparam value: $1"
  140.    egrep -o "(^|[[:space:]])$1=[^[:space:]]+" /proc/cmdline | cut -d "=" -f 2- | tail -n 1
  141. }
  142.  
  143. # Make sure the part of a script after 'mutex_lock' call is atomic,
  144. # that means the 'locked' part of the script can never be execuetd 
  145. # from several processes at the same time, in parallel.
  146. # Every script waits until it gathers the lock.
  147. # The lock directory is saved in /dev instead of /tmp, because /tmp may be
  148. # readonly at the time when the lock is needed (eg. when udev is starting)
  149. # $1 = name of the lock
  150. #
  151. mutex_lock()
  152. {
  153.    debug_log "mutex_lock" "$*"
  154.    while ! mkdir "/dev/ll-mutex-lock-$1" 2>/dev/null; do
  155.       usleep 100000;
  156.    done
  157. }
  158.  
  159. # Unlock the lock so another waiting process can reusse it and continue
  160. # $1 = name of the lock
  161. #
  162. mutex_unlock()
  163. {
  164.    debug_log "mutex_unlock" "$*"
  165.    rmdir "/dev/ll-mutex-lock-$1" 2>/dev/null
  166. }
  167.  
  168. # ===========================================================
  169. # system functions
  170. # ===========================================================
  171.  
  172. # setup /usr from /usr.lzm inside initrd
  173. mount_initrd_loops()
  174. {
  175.    debug_log "mount_initrd_loops" "$*"
  176.    if [ -e /usr.lzm ]; then
  177.       mount_device /usr.lzm /usr loop,ro squashfs
  178.    fi
  179.    if [ -e /drivers.lzm ]; then
  180.       mount_device /drivers.lzm /lib/modules/*/kernel/drivers loop,ro squashfs
  181.    fi
  182. }
  183.  
  184. # modprobe module $1, including all dependencies, suppress all messages
  185. # This was own function, because modprobe in busybox didn't support
  186. # neither gzipped modules nor dependencies. Seems to be fixed now, though.
  187. # $1 = module name, eg. ehci-hcd
  188. # $* = optional arguments
  189. #
  190. modprobe_module()
  191. {
  192.    debug_log "modprobe_module" "$*"
  193.    local MODULE
  194.  
  195.    MODULE="$1"
  196.    shift
  197.  
  198.    if [ ! "$MODULE" ]; then return 1; fi
  199.    modprobe "$MODULE" $* 2>/dev/null
  200. }
  201.  
  202. # mknod next loop device
  203. # - find biggest loop device in /dev/loop/, assume it to be used
  204. # - preallocate (mknod) 20 more loop devices in one round
  205. mknod_next_loop_dev()
  206. {
  207.    debug_log "mknod_next_loop_dev" "$*"
  208.    local i NR END PFX
  209.  
  210.    mutex_lock mknod_next_loop_dev
  211.  
  212.    if [ -d /dev/loop ]; then
  213.       NR=$(find /dev/loop/ -maxdepth 1 | sed -r 's/[^0-9]+//' | sort -n | tail -n 1)
  214.       PFX="/"
  215.    else
  216.       NR=$(find /dev/ -maxdepth 1 | grep loop | sed -r 's/[^0-9]+//' | sort -n | tail -n 1)
  217.       PFX=""
  218.    fi
  219.    NR=$(expr 0$NR + 1)
  220.    END=$(expr 0$NR + 20)
  221.    for i in $(seq $NR $END); do
  222.       mknod /dev/loop$PFX$i b 7 $i 2>/dev/null
  223.    done
  224.    echo /dev/loop$PFX$NR
  225.  
  226.    mutex_unlock mknod_next_loop_dev
  227. }
  228.  
  229. # ===========================================================
  230. # Filesystem functions
  231. # ===========================================================
  232.  
  233. # Find out what locale is requested
  234. # If no locale is given, use the firts one available (if any)
  235. # $1 = locale (optional argument, if exists, no autodetection is made)
  236. locale_id()
  237. {
  238.    debug_log "locale_id" "$*"
  239.    local LOCALE i
  240.  
  241.    # first try to find out locale from boot parameters
  242.    LOCALE="$1"
  243.    if [ "$LOCALE" = "" ]; then LOCALE=$(cmdline_value locale); fi
  244.    if [ "$LOCALE" = "" ]; then LOCALE=$(cmdline_value language); fi
  245.    if [ "$LOCALE" = "" ]; then LOCALE=$(cmdline_value lang); fi
  246.  
  247.    # if not found, set it to locale from usr/lib/locale,
  248.    # but only if there is just ONE directory, nothing more
  249.    # (so we are sure which one to use)
  250.    if [ "$LOCALE" = "" ]; then
  251.       for LOCALE in $(ls -A1p /usr/lib/locale 2>/dev/null | grep / | sed -r "s:[/]|[.].*::"); do
  252.          i="1$i"
  253.       done
  254.       if [ "$i" != "1" ]; then LOCALE=""; fi
  255.    fi
  256.  
  257.    if [ "$LOCALE" != "" ]; then
  258.       cat /usr/share/locale/locale.alias | sed -r "s/#.*//" | egrep "$LOCALE|$LOCALE""_" | tail -n 1 | tr -s "[[:space:]]" " " | cut -d " " -f 2- | tr -d " "
  259.    fi
  260. }
  261.  
  262. # Find out what iocharset to use
  263. iocharset()
  264. {
  265.    debug_log "iocharset" "$*"
  266.    local CHARSET IOCHARSET
  267.  
  268.    # if iocharset is explicitly set at the boot prompt,
  269.    # return it regardless the locale settings
  270.    IOCHARSET=$(cmdline_value iocharset)
  271.    if [ "$IOCHARSET" != "" ]; then
  272.       echo $IOCHARSET
  273.       return 0;
  274.    fi
  275.  
  276.    # else find out the iocharset from locale_id output, it should match
  277.    # some kernel module (after stripping out few of the dashes)
  278.    IOCHARSET=$(locale_id | cut -d . -f 2- | tr "[[:upper:]]" "[[:lower:]]" | tr -d -)
  279.    if [ "$IOCHARSET" = "" ]; then return 0; fi
  280.  
  281.    find /lib/modules -name "nls_*" | sed -r 's:^.*/|[.]ko$::g' | cut -b 5- | while read CHARSET; do
  282.       if [ "$(echo $CHARSET | tr "[[:upper:]]" "[[:lower:]]" | tr -d -)" = "$IOCHARSET" ]; then
  283.          echo "$CHARSET"
  284.          return 0
  285.       fi
  286.    done
  287.    return 1
  288. }
  289.  
  290. # Get filesystem options
  291. # $1 = filesystem
  292. # $2 = 'fstab' or 'mount' ... 'auto'/'noauto' string is enabled (fstab) or disabled (mount)
  293. #
  294.  
  295. fs_options()
  296. {
  297.    debug_log "fs_options" "$*"
  298.    local NOAUTO IOCHARSET
  299.  
  300.    NOAUTO=$(cmdline_parameter noauto)
  301.    if [ "$NOAUTO" = "" ]; then NOAUTO="auto"; fi
  302.    if [ "$2" = "fstab" ]; then echo -n "$NOAUTO," ; fi
  303.    if [ "$1" = "swap" ]; then echo "defaults,pri=1"; return 0; fi
  304.    echo -n "noatime,users,suid,dev,exec"
  305.  
  306.    IOCHARSET=$(iocharset)
  307.  
  308.    if [ "$1" = "vfat" ]; then
  309.       echo -n ",quiet,umask=0,check=s,shortname=mixed"
  310.       if [ "$IOCHARSET" ]; then
  311.          echo ",iocharset=$IOCHARSET"
  312.       fi
  313.    fi
  314.  
  315.    if [ "$1" = "iso9660" ]; then
  316.       echo -n ",ro"
  317.       if [ "$IOCHARSET" ]; then
  318.          echo ",iocharset=$IOCHARSET"
  319.       fi
  320.    fi
  321.  
  322.    if [ "$1" = "ntfs" ]; then
  323.       echo -n ",ro"
  324.       if [ "$IOCHARSET" ]; then
  325.          echo ",nls=$IOCHARSET"
  326.       fi
  327.    fi
  328.  
  329.    if [ "$1" = "ntfs-3g" ]; then
  330.       echo ",locale=$(locale_id)"
  331.    fi
  332. }
  333.  
  334. # discover filesystem used on the given device
  335. # Use vfat for msdos filesystem. Use ntfs-3g for ntfs if ntfsmount exists.
  336. # $1 = device, eg. /dev/hda1
  337. #
  338. device_filesystem()
  339. {
  340.    debug_log "device_filesystem" "$*"
  341.    local NTFS
  342.  
  343.    if [ -e /bin/ntfsmount ]; then NTFS="ntfs-3g"; else NTFS="ntfs"; fi
  344.    blkid -s TYPE "$1" -o value | sed "s/msdos/vfat/" | sed "s/ntfs/$NTFS/"
  345. }
  346.  
  347. # tell us if the given filesystem is supported
  348. # (eg. it's in /proc/filesystems or we know it)
  349. # $1 = filesystem name
  350. #
  351. is_supported_filesystem()
  352. {
  353.    debug_log "is_supported_filesystem" "$*"
  354.  
  355.    if [ -e /bin/ntfsmount -a "$1" = "ntfs-3g" ]; then
  356.       return 0
  357.    fi
  358.  
  359.    # the following command will set the return value
  360.    egrep -q "[[:space:]]$1\$" /proc/filesystems
  361. }
  362.  
  363. # Mount device $1 to $2
  364. # If the device is using vfat or ntfs filesystem, use iocharset as a mount option
  365. # $1 = /dev device to mount, eg. /dev/hda1, or loop file, or directory
  366. # $2 = mountpoint, eg. /mnt/hda1
  367. # $3 = optional mount options, for example "ro", or "remount,rw"
  368. # $4 = optional filesystem name, in order to skip autodetection
  369. #
  370. mount_device()
  371. {
  372.    debug_log "mount_device" "$*"
  373.    local FS DEV LOOPDEV OPTIONS FILESYSTEM ERR
  374.  
  375.    # make sure we have enough arguments
  376.    if [ "$2" = "" ]; then return 1; fi
  377.    if [ "$1" = "" ]; then rmdir "$2" 2>/dev/null; return 1; fi
  378.    mkdir -p "$2"
  379.  
  380.    DEV="$1"
  381.    if [ "$4" != "" ]; then FS="$4"; else FS=$(device_filesystem "$1"); fi
  382.    if [ "$FS" ]; then OPTIONS=$(fs_options $FS mount); FS="-t $FS"; fi
  383.    if [ "$OPTIONS" ]; then OPTIONS="$OPTIONS"; else OPTIONS=""; fi
  384.    if [ -f "$DEV" ]; then OPTIONS="$OPTIONS,loop"; fi
  385.    if [ -d "$DEV" ]; then OPTIONS="$OPTIONS,rbind"; fi
  386.    if [ "$3" ]; then OPTIONS="$OPTIONS,$3"; fi
  387.    OPTIONS=$(echo "$OPTIONS" | sed -r "s/^,+//")
  388.  
  389.    if [ "$FS" = "-t ntfs-3g" ]; then
  390.       ntfsmount "$DEV" "$2" -o $OPTIONS >/dev/null 2>&1
  391.       ERR=$?
  392.    else
  393.       mount -n -o $OPTIONS $FS "$DEV" "$2" >/dev/null 2>&1
  394.       ERR=$?
  395.    fi
  396.  
  397.    # not enough loop devices? try to create one.
  398.    if [ $ERR -eq 2 ]; then
  399.        LOOPDEV=$(mknod_next_loop_dev)
  400.        OPTIONS=$(echo "$OPTIONS" | sed -r "s/,loop//g")
  401.        losetup "$LOOPDEV" "$DEV" 2>/dev/null # busybox's losetup doesn't support -r
  402.        if [ $? -ne 0 ]; then
  403.           losetup -r "$LOOPDEV" "$DEV" 2>/dev/null # force read-only in case of error
  404.        fi
  405.        mount -n -o $OPTIONS $FS "$LOOPDEV" "$2" >/dev/null 2>&1
  406.        ERR=$?
  407.    fi
  408.  
  409.    # if nothing works, try to force read-only mount
  410.    if [ $ERR -ne 0 ]; then
  411.        mount -n -r -o $OPTIONS $FS "$DEV" "$2" >/dev/null 2>&1
  412.        ERR=$?
  413.    fi
  414.  
  415.    if [ $ERR -ne 0 ]; then rmdir $2 2>/dev/null; fi
  416.    return $ERR
  417. }
  418.  
  419. # unmount all parameters. If the parameter is not mountpoint but
  420. # it's a file or directory, umount the device where the file/dir is stored.
  421. #
  422. # First try normal umount, if that fails then remount read-only
  423. # If -l parameter is specified, do lazy-umount when normal umount fails
  424. # $1..$n = files/directories/devices to be unmounted
  425. #
  426. fumount()
  427. {
  428.    debug_log "fumount" "$*"
  429.    local TARGET LAZY
  430.  
  431.    while [ "$1" ]; do
  432.       if [ "$1" = "-l" ]; then LAZY="yes"; shift; fi
  433.       TARGET=$(readlink -f "$1")
  434.       if ! ismountpoint "$TARGET"; then
  435.          if [ -f "$TARGET" -o -d "$TARGET" ]; then
  436.             TARGET=$(df "$TARGET" | tail -n 1 | tr -s " " | cut -d " " -f 6)
  437.          fi
  438.       fi
  439.  
  440.       if [ "$TARGET" != "" ]; then
  441.          umount -n "$TARGET" >/dev/null 2>&1
  442.          if [ $? -ne 0 ]; then
  443.             mount -n -o remount,ro -t ignored ignored "$TARGET" >/dev/null 2>&1
  444.             if [ "$LAZY" ]; then umount -n -l "$TARGET" >/dev/null 2>&1; fi
  445.          fi
  446.       fi
  447.       shift
  448.    done
  449. }
  450.  
  451. # ===========================================================
  452. # live module functions
  453. # ===========================================================
  454.  
  455. # Create module
  456. # call mksquashfs with apropriate arguments
  457. # $1 = directory which will be compressed to squashfs module
  458. # $2 = output filesystem module file
  459. # $3..$9 = optional arguments like -keep-as-directory or -b 123456789
  460. #
  461. create_module()
  462. {
  463.    debug_log "create_module" "$*"
  464.    rm -f "$2" # overwrite, never append to existing file
  465.    mksquashfs "$1" "$2" -b 256K -lzmadic 256K $3 $4 $5 $6 $7 $8 $9>/dev/null
  466.    if [ $? -ne 0 ]; then return 1; fi
  467.    chmod a-wx "$2" # remove execute and write attrib
  468.    chmod a+r "$2" # add read for everyone
  469. }
  470.  
  471. # ismountpoint exits with 0 if $1 is mountpoint, else exits with 1
  472. # $1 = directory or loop_file
  473. #
  474. ismountpoint()
  475. {
  476.    debug_log "ismountpoint" "$*"
  477.    local MDIR
  478.  
  479.    MDIR=$(readlink -f "$1")
  480.    cat /proc/mounts | cut -d " " -f 2 | egrep "^$MDIR\$" >/dev/null 2>&1
  481. }
  482.  
  483. # Mount filesystem module to destination directory
  484. # $1 = path to the compressed module
  485. # $2 = destination folder
  486. #
  487. mount_module()
  488. {
  489.    debug_log "mount_module" "$*"
  490.    mount_device "$1" "$2" loop,ro squashfs
  491. }
  492.  
  493. # Insert a directory tree $2 to an union specified by $1
  494. # Top-level read-write branch is specified by it's index 0
  495. # Using =rr enables aufs to optimize real readonly branches
  496. # $1 = union absolute path (starting with /)
  497. # $2 = path to data directory
  498. #
  499. union_insert_dir()
  500. {
  501.    debug_log "union_insert_dir" "$*"
  502.    mount -n -o remount,add:1:$2=rr aufs $1
  503. }
  504.  
  505. # Find LZM modules in given dir
  506. # $1 = root directory of mounted DATAdir
  507. #
  508. find_modules()
  509. {
  510.    debug_log "find_modules" "$*"
  511.    find "$1/base" "$1/modules" "$1/optional" -name "*.lzm" 2>/dev/null | sort
  512. }
  513.  
  514. # List all modules in all directories (base, modules, optional)
  515. # and filter out unneeded optional modules (not specified by load= kernel parameter)
  516. # separator for load and noload arguments is "," or ";"
  517. # $1 = root directory of mounted DATAdir
  518. #
  519. list_modules()
  520. {
  521.    debug_log "list_modules" "$*"
  522.    local LOAD NOLOAD
  523.  
  524.    LOAD=$(cmdline_value load | sed -r 's/\*/.\*/g' | sed -r 's/,|;/|/g')
  525.    NOLOAD=$(cmdline_value noload | sed -r 's/\*/.\*/g' | sed -r 's/,|;/|/g')
  526.    find_modules "$1" | while read LINE; do
  527.       MODNAME=$(echo $LINE | cut -b ${#1}- | cut -b 2-)
  528.       if [ "$(echo $LINE | grep /optional/)" ]; then
  529.          if [ ! "$LOAD" -o ! "$(echo $MODNAME | egrep -i "$LOAD")" ]; then continue; fi
  530.       fi
  531.       if [ "$NOLOAD" -a "$(echo $MODNAME | egrep -i "$NOLOAD")" ]; then continue; fi
  532.       echo $LINE
  533.    done
  534. }
  535.  
  536. # Insert one single filesystem module to the union
  537. # $1 = union absolute path
  538. # $2 = module full path
  539. # $3 = destination folder, where images will be mounted to
  540. # $4 = preffix length strip (number of characters)
  541. #
  542. union_insert_module()
  543. {
  544.    debug_log "union_insert_module" "$*"
  545.    local TARGET
  546.  
  547.    TARGET="$3/$(basename $2)"
  548.    if ismountpoint $TARGET; then return 1; fi # skip already used modules
  549.    mkdir -p $TARGET
  550.    mount_module $2 $TARGET
  551.    if [ $? -ne 0 ]; then echo "Cannot read module data. corrupted download?" >&2; return 1; fi
  552.    union_insert_dir $1 $TARGET
  553.    if [ $? -ne 0 ]; then echo "can't insert module to union" >&2; return 2; fi
  554.    echo "$2" | cut -b $(($4+1))-
  555.    echolog "$2" >/dev/null
  556.    return 0
  557. }
  558.  
  559. # Insert all filesystem modules from $2 directory and subdirectories, to the union
  560. # $1 = union absolute path (starting with /)
  561. # $2 = LiveCD data dir (with directories /base, /modules, etc.)
  562. # $3 = destination folder, where images will be mounted to
  563. #
  564. union_insert_modules()
  565. {
  566.    debug_log "union_insert_modules" "$*"
  567.    local INSERTED
  568.  
  569.    list_modules $2 | while read MODULE; do
  570.       INSERTED=$(union_insert_module $1 $MODULE $3 ${#2})
  571.       if [ "$INSERTED" != "" ]; then echolog " -> $(echo $INSERTED | sed -r s:^/::)"; fi
  572.    done
  573. }
  574.  
  575. # Copy LiveCD modules to RAM directory
  576. # will copy only /boot, and module files from $1
  577. # $1 = data directory
  578. # $2 = target directory in RAM
  579. #
  580. copy_to_ram()
  581. {
  582.    debug_log "copy_to_ram" "$*"
  583.    cp -a "$1/rootcopy" "$2" 2>/dev/null # could be empty
  584.    list_modules "$1" | while read MODULE; do
  585.       TARGET=$(dirname "$MODULE" | cut -b ${#1}- | cut -b 2-)
  586.       mkdir -p "$2/$TARGET"
  587.       cp "$MODULE" "$2/$TARGET"
  588.       if [ $? -ne 0 ]; then fatal "Not enough memory. Using ramsize=$RAMSIZE"; fi
  589.    done
  590. }
  591.  
  592. # ===========================================================
  593. # discovery functions
  594. # ===========================================================
  595.  
  596. # List all supported network drivers
  597. #
  598. list_network_drivers()
  599. {
  600.    debug_log "list_network_drivers" "$*"
  601.  
  602.    # these drivers are probed in Slackware's initrd
  603.    # (see initrd.img/scripts/network.sh).
  604.    # I don't have personal experiences with most of these drivers
  605.    # so I'll be happy if you report any particular one to be not working
  606.    # (eg. causing hangups) in order to remove it from this list.
  607.  
  608.    echo 3c59x acenic atl1 de4x5 dgrs eepro100 e1000 epic100 hp100 ne2k-pci \
  609.    olympic pcnet32 r8169 rcpci 8139too 8139cp sktr skge sky2 tulip via-rhine \
  610.    yellowfin tg3 dl2k ns83820 depca ibmtr 3c501 3c503 3c505 3c507 3c509 3c515 \
  611.    ac3200 acenic at1700 cosa cs89x0 de4x5 de600 de620 e2100 eepro eexpress \
  612.    es3210 eth16i ewrk3 fmv18x forcedeth hostess_sv11 hp-plus hp lne390 ne3210 \
  613.    ni5010 ni52 ni65 sb1000 sealevel smc-ultra sis900 smc-ultra32 smc9194 wd \
  614.    | tr " " "\n"
  615. }
  616.  
  617. # List all CD-ROMs
  618. # by using /proc entries
  619. #
  620. list_cdrom_devices()
  621. {
  622.    debug_log "list_cdrom_devices" "$*"
  623.    local CDDEVICE
  624.  
  625.    for CDDEVICE in $(cat /proc/sys/dev/cdrom/info 2>/dev/null | head -n 3 | tail -n 1 | cut -d ":" -f 2); do
  626.       echo "/dev/$CDDEVICE"
  627.    done
  628. }
  629.  
  630. # List all mounted directories
  631. #
  632. list_mounted_directories()
  633. {
  634.    debug_log "list_mounted_directories" "$*"
  635.    if [ "$MOUNTDIR" ]; then
  636.       ls -1 $MOUNTDIR | while read DIR; do
  637.          if ismountpoint $MOUNTDIR/$DIR; then echo $DIR; fi
  638.       done
  639.    fi
  640. }
  641.  
  642. # List all devices with filesystems
  643. # Return empty result when nohd parameter was given.
  644. #
  645. list_partition_devices()
  646. {
  647.    debug_log "list_partition_devices" "$*"
  648.    if [ "$(cmdline_parameter nohd)" != "" ]; then return 1; fi
  649.    cat /proc/partitions | grep -v loop | grep -v major | grep -v '^$' | sed -r "s:^[0-9 ]+:/dev/:"
  650.    if [ -e /dev/mapper/control ]; then # list LVM partitions if available
  651.       ls -1 /dev/mapper/ | grep -v "^control\$" | sed -r "s:^:/dev/mapper/:"
  652.    fi
  653. }
  654.  
  655. # List all disk devices
  656. #
  657. list_disk_devices()
  658. {
  659.    debug_log "list_disk_devices" "$*"
  660.    list_partition_devices | egrep -v "[0-9]"
  661. }
  662.  
  663. # List all partitions marked as Linux Swap
  664. #
  665. list_swap_devices()
  666. {
  667.    debug_log "list_swap_devices" "$*"
  668.    if [ "$(cmdline_parameter nohd)" != "" -o "$(cmdline_parameter noswap)" != "" ]; then return 1; fi
  669.    blkid -t TYPE="swap" -o device
  670. }
  671.  
  672. # List all block devices
  673. #
  674. list_block_devices()
  675. {
  676.    debug_log "list_block_devices" "$*"
  677.    if [ "$(cmdline_parameter nocd)" = "" ]; then
  678.       list_cdrom_devices
  679.    fi
  680.    list_partition_devices
  681. }
  682.  
  683. # Format mountdir for device. This function used to append _cdrom or _removable
  684. # suffix to the directory name so KDE was able to assign a nice icon for evey
  685. # device, but this should be done using HAL in KDE nowadays, so we do not
  686. # support these stupid suffixes anymore. Many people will be happy :)
  687. # $1 = device full path, eg. /dev/hda1
  688. #
  689. device_mountdir()
  690. {
  691.    debug_log "device_mountdir" "$*"
  692.    echo "/$MOUNTDIR/$(basename "$1")" | tr -s /
  693. }
  694.  
  695. # Find file-path on given device
  696. # First it mounts the device read-only. If then the 'path' is found, 
  697. # then remount without RO flag (causes it to be mounted read-write if possible)
  698. # and return the path, else unmount and exit.
  699. # If the device/dev_directory is already mounted, preserve it mounted
  700. # $1 = device
  701. # $2 = path/filename
  702. #
  703. find_filepath()
  704. {
  705.    debug_log "find_filepath" "$*"
  706.    local DIR FOUND PRESERVE
  707.  
  708.    DIR=$(device_mountdir $1)
  709.    ismountpoint $DIR
  710.    if [ $? -eq 0 ]; then
  711.       PRESERVE="true"
  712.    else
  713.       mount_device $1 $DIR ro
  714.       if [ $? -ne 0 ]; then rmdir $DIR 2>/dev/null; return 1; fi
  715.       PRESERVE=""
  716.    fi
  717.  
  718.    FOUND=$(ls -A1d $DIR/$2 2>/dev/null | head -n 1 | tr -s '/')
  719.  
  720.    if [ "$FOUND" = "" ]; then
  721.       if [ "$PRESERVE" != "true" ]; then
  722.          fumount $DIR
  723.          rmdir $DIR 2>/dev/null
  724.       fi
  725.       return 1
  726.    else
  727.       # remount without the 'ro' option now, so use rw or defaults
  728.       # Only in the case it was not mounted already before.
  729.       if [ "$PRESERVE" != "true" ]; then
  730.          fumount $DIR
  731.          mount_device $1 $DIR
  732.          if [ $? -ne 0 ]; then
  733.             rmdir $DIR 2>/dev/null
  734.         return 2
  735.      fi
  736.       fi
  737.       echo "$FOUND"
  738.       return 0
  739.    fi
  740. }
  741.  
  742. # Find file in computer by mounting disks or other storage devices
  743. # and searching for $1 in the mounted directory
  744. # $1 = filename or device-path or devicepath/filename
  745. #
  746. find_file()
  747. {
  748.    debug_log "find_file" "$*"
  749.    local FIND DEVICE DEVPART PATHPART
  750.  
  751.    # allow using /mnt/... as well as /dev/...
  752.    FIND=$(echo "$1" | sed -r "s:^/mnt/:/dev/:")
  753.  
  754.    # if parameter is just a device, echo it and exit
  755.    if [ -b "$FIND" -o -c "$FIND" -o "$FIND" = "" ]; then echo "$FIND"; return; fi
  756.  
  757.    # If path doesn't start with /dev/, try to find the exact path on all devices
  758.    # First, split DEV/PATH parts
  759.    DEVPART=$(echo "$FIND" | egrep -o "^/dev/[^/]+")
  760.  
  761.    if [ "$DEVPART" = "" ]; then
  762.       # no device is specified. Search all devices for filename $FIND
  763.       PATHPART="$FIND";
  764.       for DEVICE in $(list_mounted_directories) $(list_block_devices); do
  765.          if ! grep -q ":$DEVICE@$PATHPART:" /tmp/_findfile 2>/dev/null; then
  766.             find_filepath "$DEVICE" "$PATHPART"
  767.             if [ $? -eq 0 ]; then return 0; fi
  768.             echo ":$DEVICE@$PATHPART:" >>/tmp/_findfile
  769.          fi
  770.       done
  771.    else
  772.       # try to find PATHPART only on the given device
  773.       PATHPART=$(echo "$FIND" | sed -r 's:^/dev/[^/]+(.*):\1:')
  774.       find_filepath $DEVPART $PATHPART
  775.    fi
  776. }
  777.  
  778. # Find In Computer
  779. # use 'find_file' function to find the given file/dir
  780. # if nothing found, sleep for a while to allow devices to settle and try again.
  781. # (is there any way to find out if there are devices queued through /sys?)
  782. # $1 = file or directory to find
  783. #
  784. find_in_computer()
  785. {
  786.    debug_log "find_in_computer" "$*"
  787.    local TIMEOUT RESULT
  788.  
  789.    TIMEOUT=$(cmdline_value scantimeout | sed -r 's/[^0-9]*([0-9]+).*/\1/')
  790.    if [ "$TIMEOUT" = "" ]; then TIMEOUT=10; fi
  791.  
  792.    RESULT=$(find_file "$1")
  793.  
  794.    while [ $TIMEOUT -gt 0 -a "$RESULT" = "" ]; do
  795.       echo -ne "- wait a while\r" >&2
  796.       sleep 1
  797.       TIMEOUT=$((TIMEOUT-1))
  798.       RESULT=$(find_file "$1")
  799.    done
  800.  
  801.    echo $RESULT
  802. }
  803.  
  804. # Find and run all scripts from the given module
  805. # This function is used by the activate and deactivate script when the distro
  806. # is already started, not during live setup
  807. # $1 = mounted module full path
  808. # $2..$n = optional arguments for the scripts, eg. 'start'
  809. #
  810. find_n_run_scripts()
  811. {
  812.    debug_log "find_n_run_scripts" "$*"
  813.    local MOD
  814.  
  815.    MOD="$1"
  816.    shift
  817.  
  818.    if [ -d $MOD/etc/rc.d -o -d $MOD/etc/rc.d/init.d -o -d $MOD/etc/init.d ]; then
  819.       ( find $MOD/etc/rc.d -type f -maxdepth 1 2>/dev/null ; \
  820.         find $MOD/etc/init.d -type f -maxdepth 1 2>/dev/null  ; \
  821.         find $MOD/etc/rc.d/init.d -type f -maxdepth 1 2>/dev/null \
  822.       ) | cut -b ${#MOD}- | cut -b 2- | xargs -n 1 -r readlink -f | sort -u | while read SCRIPT; do
  823.          if [ "$SCRIPT" != "" -a -x "$SCRIPT" -a ! -d "$SCRIPT" ]; then
  824.             # call the script by real path, not from the module
  825.             log "starting '$SCRIPT $@'"
  826.             ${SCRIPT} "$@"
  827.          fi
  828.       done
  829.    fi
  830. }
  831.  
  832. # ===========================================================
  833. # hardware preparation functions
  834. # ===========================================================
  835.  
  836. # Create block devices to /dev described by /sys entries
  837. #
  838. mdev_start_hotplug()
  839. {
  840.    debug_log "mdev_start_hotplug" "$*"
  841.    echolog "creating /dev entries for block devices"
  842.    mdev -s
  843.    rm /dev/pty??* /dev/tty??* # remove unneeded pty and tty devices
  844.    echo /bin/mdev > /proc/sys/kernel/hotplug # use mdev as a hotplug handler
  845. }
  846.  
  847. # Modprobe kernel modules needed for the LiveCD
  848. #
  849. modprobe_essential_modules()
  850. {
  851.    debug_log "modprobe_essential_modules" "$*"
  852.  
  853.    echolog "starting loop device support"
  854.    modprobe_module loop
  855.    echolog "starting cdrom filesystem support"
  856.    modprobe_module isofs
  857.    echolog "starting squashfs support"
  858.    modprobe_module squashfs
  859.    echolog "starting aufs support with brs=1"
  860.    modprobe_module aufs brs=1
  861.    echolog "starting linux filesystem support"
  862.    modprobe_module ext2
  863.    modprobe_module ext3
  864.    modprobe_module reiserfs
  865.    modprobe_module xfs
  866.    modprobe_module vfat
  867.    echolog "starting windows filesystem support"
  868.    modprobe_module vfat
  869.    modprobe_module fuse # for ntfs-3g
  870.    modprobe_module ntfs # for ro driver
  871. }
  872.  
  873. # Modprobe kernel modules needed for USB masstorage devices
  874. #
  875. modprobe_usb_modules()
  876. {
  877.    debug_log "modprobe_usb_modules" "$*"
  878.    local LSPCI
  879.  
  880.    # skip module loading if nohotplug bootparam is present
  881.    if [ "$(cmdline_parameter nohotplug)" ]; then return 0; fi
  882.  
  883.    LSPCI=$(lspci -v | grep -i prog-if)
  884.    if [ "$(echo $LSPCI | egrep -i [eou]hci)" = "" ]; then
  885.       return 0
  886.    fi
  887.  
  888.    echolog "starting USB support"
  889.    if [ "$(echo $LSPCI | grep -i ehci)" != "" ]; then
  890.       modprobe_module ehci-hcd
  891.    fi
  892.    if [ "$(echo $LSPCI | grep -i ohci)" != "" ]; then
  893.       modprobe_module ohci-hcd
  894.    fi
  895.    if [ "$(echo $LSPCI | grep -i uhci)" != "" ]; then
  896.       modprobe_module uhci-hcd
  897.    fi
  898.    modprobe_module usb-storage
  899. }
  900.  
  901. # Load drivers for PCMCIA CardBus devices
  902. #
  903. modprobe_pcmcia_modules()
  904. {
  905.    debug_log "modprobe_pcmcia_modules" "$*"
  906.  
  907.    # skip module loading if nohotplug bootparam is present
  908.    if [ "$(cmdline_parameter nohotplug)" ]; then return 0; fi
  909.  
  910.    echolog "starting PCMCIA CardBus support"
  911.    modprobe_module pcmcia_core
  912.    modprobe_module pcmcia
  913.    modprobe_module rsrc_nonstatic
  914.    modprobe_module yenta_socket
  915. }
  916.  
  917. # Load network drivers unless eth[0-9] is found
  918. #
  919. modprobe_network_modules()
  920. {
  921.    debug_log "modprobe_network_modules" "$*"
  922.    local ETH
  923.  
  924.    # skip module loading if nohotplug bootparam is present
  925.    if [ "$(cmdline_parameter nohotplug)" ]; then return 0; fi
  926.  
  927.    # probe all drivers. Start by the ones mentioned in pcimodules' output
  928.    for module in $(list_network_drivers | egrep "$(pcimodules | tr "\n" "|")!") $(list_network_drivers); do
  929.       modprobe_module $module
  930.       ETH=$(cat /proc/net/dev | grep : | grep -v lo: | cut -d : -f 1 | tr -d " ")
  931.       if [ "$ETH" != "" ]; then
  932.          echo $ETH
  933.          return 0
  934.       fi
  935.       rmmod $module 2>/dev/null
  936.    done
  937. }
  938.  
  939. # Start udhcpc to get IP address from DHCP server
  940. # $1 = interface to use (optional)
  941. #
  942. init_dhcp()
  943. {
  944.    debug_log "start_dhcp_client" "$*"
  945.  
  946.    if [ "$1" != "" ]; then
  947.       ifconfig $1 up
  948.       udhcpc -i $1 -q
  949.    else
  950.       ifconfig eth0 up
  951.       udhcpc -q
  952.    fi
  953. }
  954.  
  955. # Mount http filesystem from the given server
  956. # $1 = server
  957. # $2 = mountdir
  958. #
  959. mount_httpfs()
  960. {
  961.    debug_log "mount_httpfs" "$*"
  962.  
  963.    mkdir -p $2
  964.    httpfs $1 $2
  965. }
  966.  
  967.  
  968. # Unload modules loaded to kernel which are not used
  969. # This function used to unload more modules, but it may cause
  970. # problems to auto-remove some of them (eg. a network module 
  971. # can seem unneeded even if network is to be used very soon.
  972. #
  973. rmmod_unused_modules()
  974. {
  975.    debug_log "rmmod_unused_modules" "$*"
  976.    rmmod usb-storage uhci-hcd ohci-hcd ehci-hcd 2>/dev/null
  977.    rmmod yenta_socket rsrc_nonstatic pcmcia pcmcia_core 2>/dev/null
  978. }
  979.  
  980. # kill all unneeded processes, which have bigger PID then the PID of
  981. # current shell. We can't use killall5, as it would kill some processes
  982. # which may be currently needed, for example ntfsmount.
  983. # $1 = maximum pid (kill all lower)
  984. #
  985. killall_unneeded()
  986. {
  987.    debug_log "killall_unneeded" "$*"
  988.    local LIST PID
  989.  
  990.    PID=$1
  991.    for pid in $(ps | grep -v "PID" | egrep -v "\[.*\]" | fgrep -v mount | fgrep -v posixovl | fgrep -v ntfs | sed -r "s/^[[:space:]]*([0-9]+).*/\\1/"); do
  992.       if [ $pid -lt $PID ]; then
  993.          LIST="$LIST $pid"
  994.       fi
  995.    done
  996.  
  997.    kill -SIGTERM $LIST 2>/dev/null # SIGTERM
  998.    sleep 2
  999.    kill -SIGKILL $LIST 2>/dev/null # SIGKILL
  1000. }
  1001.  
  1002. # enable/disable CD autoejecting when unmounted
  1003. # $1 = 1|0 ... enable|disable
  1004. #
  1005. cd_autoeject()
  1006. {
  1007.    debug_log "cd_autoeject" "$*"
  1008.    echo $1 >/proc/sys/dev/cdrom/autoeject
  1009. }
  1010.  
  1011. # ===========================================================
  1012. # FSTAB functions
  1013. # ===========================================================
  1014.  
  1015. # $1 = fstab file
  1016. # $2 = device name
  1017. dev_is_in_fstab()
  1018. {
  1019.    debug_log "dev_is_in_fstab" "$*"
  1020.    cat "$1" | sed -r "s/#.*//" | egrep -q "^[[:space:]]*$2[[:space:]]"
  1021. }
  1022.  
  1023. # update given line in fstab, add new values only if the device is not found
  1024. # $1 = fstab file to parse
  1025. # $2 = device name
  1026. # $3 = mountpoint
  1027. # $4 = filesystem
  1028. # $5 = mount options
  1029. #
  1030. fstab_add_line()
  1031. {
  1032.    debug_log "fstab_add_line" "$*"
  1033.    local DIR
  1034.  
  1035.    if [ "$4" != "swap" ]; then DIR="$3"; else DIR="none"; fi
  1036.    if ! dev_is_in_fstab "$1" "$2"; then
  1037.       echo "$2" "$DIR" "$4" "$5" 0 0 "$FSTABLLFLAG" >>$1
  1038.    fi
  1039. }
  1040.  
  1041. # create correct fstab file in $1/etc/fstab and create apropriate
  1042. # mount directories in $1/mnt. This function is only calld once,
  1043. # during liveCD startup (even before init from the distro is started).
  1044. # $1 = root directory (union)
  1045. #
  1046. fstab_update()
  1047. {
  1048.    debug_log "fstab_update" "$*"
  1049.    local FSTAB FSTABTMP
  1050.  
  1051.    FSTAB="$1/etc/fstab"
  1052.    FSTABTMP=$FSTAB$$
  1053.    mkdir -p $1/etc $1/mnt
  1054.    cat $FSTAB 2>/dev/null | grep -v "$FSTABLLFLAG" >$FSTABTMP
  1055.  
  1056.    fstab_add_line $FSTABTMP aufs / aufs defaults
  1057.    fstab_add_line $FSTABTMP proc /proc proc defaults
  1058.    fstab_add_line $FSTABTMP sysfs /sys sysfs defaults
  1059.    fstab_add_line $FSTABTMP devpts /dev/pts devpts gid=5,mode=620
  1060.    fstab_add_line $FSTABTMP tmpfs /dev/shm tmpfs defaults
  1061.  
  1062.    list_cdrom_devices | while read DEVICE; do
  1063.       MNT=$(device_mountdir $DEVICE)
  1064.       FS=$(device_filesystem $DEVICE)
  1065.       if [ "$FS" = "" ]; then FS=iso9660; fi
  1066.       mkdir -p "$1/$MNT"
  1067.       fstab_add_line $FSTABTMP $DEVICE $MNT $FS $(fs_options $FS fstab)
  1068.    done
  1069.    list_partition_devices | while read DEVICE; do
  1070.       MNT=$(device_mountdir $DEVICE)
  1071.       FS=$(device_filesystem $DEVICE)
  1072.       OPT=$(fs_options $FS fstab)
  1073.  
  1074.       if [ "$FS" = "swap" ]; then
  1075.          fstab_add_line $FSTABTMP $DEVICE $MNT $FS $OPT
  1076.       fi
  1077.  
  1078.       # If the partition has a valid filesystem, add it to fstab
  1079.       if is_supported_filesystem "$FS"; then
  1080.          fstab_add_line $FSTABTMP $DEVICE $MNT $FS $OPT
  1081.          mkdir -p "$1/$MNT"
  1082.       fi
  1083.    done
  1084.  
  1085.    mv -f $FSTABTMP $FSTAB
  1086. }
  1087.